home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / DirectInput / DIConfig / flexscrollbar.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  10.7 KB  |  507 lines

  1. //-----------------------------------------------------------------------------
  2. // File: flexscrollbar.cpp
  3. //
  4. // Desc: Implements CFlexScrollBar (derived from CFlexWnd), a scroll bar
  5. //       control similar to a Windows scroll bar.
  6. //
  7. // Copyright (C) Microsoft Corporation. All Rights Reserved.
  8. //-----------------------------------------------------------------------------
  9.  
  10. #include "common.hpp"
  11.  
  12.  
  13. CFlexScrollBar::CFlexScrollBar() :
  14.     m_nMin(0),
  15.     m_nMax(0),
  16.     m_nPage(25),
  17.     m_nPos(25),
  18.     m_bVert(TRUE),
  19.     m_hWndNotify(NULL),
  20.     m_bValid(FALSE),
  21.     m_bCapture(FALSE),
  22.     m_bDragging(FALSE),
  23.     m_code(SB_ENDSCROLL),
  24.     m_rgbBk(RGB(0,0,0)),
  25.     m_rgbFill(RGB(0,0,255)),
  26.     m_rgbLine(RGB(0,255,255))
  27. {
  28. }
  29.  
  30. CFlexScrollBar::~CFlexScrollBar()
  31. {
  32. }
  33.  
  34. CFlexScrollBar *CreateFlexScrollBar(FLEXSCROLLBARCREATESTRUCT *pcs)
  35. {
  36.     CFlexScrollBar *psb = new CFlexScrollBar;
  37.     
  38.     if (psb && psb->Create(pcs))
  39.         return psb;
  40.     
  41.     delete psb;
  42.     return NULL;
  43. }
  44.  
  45. BOOL CFlexScrollBar::Create(FLEXSCROLLBARCREATESTRUCT *pcs)
  46. {
  47.     if (this == NULL)
  48.         return FALSE;
  49.  
  50.     if (pcs == NULL)
  51.         return FALSE;
  52.  
  53.     if (pcs->dwSize != sizeof(FLEXSCROLLBARCREATESTRUCT))
  54.         return FALSE;
  55.  
  56.     if (pcs->min > pcs->max)
  57.         return FALSE;
  58.  
  59.     int range = pcs->max - pcs->min;
  60.  
  61.     if (pcs->page > range)
  62.         return FALSE;
  63.  
  64.     m_bVert = ( pcs->dwFlags & FSBF_VERT ) == FSBF_VERT;
  65.  
  66.     SetValues(pcs->min, pcs->max, pcs->page, pcs->pos);
  67.  
  68.     m_hWndNotify = pcs->hWndNotify ? pcs->hWndNotify : pcs->hWndParent;
  69.  
  70.     if (!CFlexWnd::Create(pcs->hWndParent, pcs->rect, pcs->bVisible))
  71.         return FALSE;
  72.  
  73.     Calc();
  74.  
  75.     return TRUE;
  76. }
  77.  
  78. int CFlexScrollBar::GetLineAdjust()
  79. {
  80.     return 1;
  81. }
  82.  
  83. int CFlexScrollBar::GetPageAdjust()
  84. {
  85.     return m_nPage > 1 ? m_nPage - 1 : 1;
  86. }
  87.  
  88. void CFlexScrollBar::AdjustPos(int adj, BOOL bForceCalc)
  89. {
  90.     int old = m_nPos;
  91.  
  92.     m_nPos += adj;
  93.  
  94.     if (m_nPos < m_nMin)
  95.         m_nPos = m_nMin;
  96.     if (m_nPos > m_nMax - m_nPage)
  97.         m_nPos = m_nMax - m_nPage;
  98.  
  99.     if (m_nPos == old && !bForceCalc)
  100.         return;
  101.  
  102.     if (Calc())
  103.         Invalidate();
  104. }
  105.  
  106. BOOL CFlexScrollBar::FailCalc(BOOL bOldValid)
  107. {
  108.     m_bValid = FALSE;
  109.     if (bOldValid)
  110.         Invalidate();
  111.     return m_bValid;
  112. }
  113.  
  114. BOOL CFlexScrollBar::Calc()
  115. {
  116.     BOOL bOldValid = m_bValid;
  117. #define FAIL return FailCalc(bOldValid)
  118.  
  119.     if (!m_hWnd)
  120.         FAIL;
  121.  
  122.     SRECT zero;
  123.     m_rectLineUp = zero;
  124.     m_rectPageUp = zero;
  125.     m_rectTrack = zero;
  126.     m_rectThumb = zero;
  127.     m_rectPageDown = zero;
  128.     m_rectLineDown = zero;
  129.  
  130.     SPOINT size = GetClientSize();
  131.  
  132.     int ord = m_bVert ? 1 : 0;
  133.     int nord = m_bVert ? 0 : 1;
  134.     int length = size.a[ord];
  135.     int width = size.a[nord];
  136.     int arrowlen = width;
  137.  
  138.     if (width < 1 || length < 2)
  139.         FAIL;
  140.  
  141.     int tracklen = length - arrowlen * 2;
  142.     int trackofs = arrowlen;
  143.  
  144.     BOOL bOverlappingArrows = tracklen < -1;
  145.     int overlap = !bOverlappingArrows ? 0 : -tracklen;
  146.  
  147.     SRECT up, down, track, thumb, temp;
  148.  
  149.     if (overlap > 1)
  150.     {
  151.         int mid = length / 2;
  152.         up.lr.a[nord] = width;
  153.         up.lr.a[ord] = mid;
  154.         down.ul.a[ord] = mid;
  155.         down.lr.a[ord] = length;
  156.         down.lr.a[nord] = width;
  157.         m_rectLineUp = up;
  158.         m_rectLineDown = down;
  159.         return m_bValid = TRUE;
  160.     }
  161.  
  162.     up.lr.a[nord] = width;
  163.     up.lr.a[ord] = arrowlen;
  164.     down.lr.a[nord] = width;
  165.     down.ul.a[ord] = length - arrowlen;
  166.     down.lr.a[ord] = length;
  167.     m_rectLineUp = up;
  168.     m_rectLineDown = down;
  169.  
  170.     int tmin = up.lr.a[ord];
  171.     int tmax = down.ul.a[ord];
  172.     int trange = tmax - tmin;
  173.     int range = m_nMax - m_nMin;
  174.     assert(trange > 0);
  175.     if (!(range > 0) || !(trange > 0))
  176.         return m_bValid = TRUE;
  177.  
  178.     track.ul.a[ord] = tmin;
  179.     track.lr.a[nord] = width;
  180.     track.lr.a[ord] = tmax;
  181.     m_rectTrack = track;
  182.  
  183.     const int minthumblen = 3;
  184.     int thumblen = MulDiv(m_nPage, trange, range);
  185.     if (thumblen < minthumblen)
  186.         thumblen = minthumblen;
  187.  
  188.     int thumbrange = trange - thumblen /*+ 1*/;
  189.     int pagerange = range - m_nPage;
  190.     if (!(pagerange > 1) || !(thumbrange > 1))
  191.         return m_bValid = TRUE;
  192.     int logpos = m_bDragging ? m_nPreDragPos : m_nPos;
  193.     int thumbpos = MulDiv(logpos - m_nMin, thumbrange, pagerange) + tmin;
  194.     if (m_bDragging)
  195.     {
  196.         SPOINT rp = m_point, rs = m_startpoint;
  197.         int rdelta = rp.a[ord] - rs.a[ord];
  198.         thumbpos += rdelta;
  199.         if (thumbpos < tmin)
  200.             thumbpos = tmin;
  201.         if (thumbpos > tmax - thumblen)
  202.             thumbpos = tmax - thumblen;
  203.         m_nThumbPos = MulDiv(thumbpos - tmin, pagerange, thumbrange) + m_nMin;
  204.         if (m_nThumbPos < m_nMin)
  205.             m_nThumbPos = m_nMin;
  206.         if (m_nThumbPos > m_nMax - m_nPage)
  207.             m_nThumbPos = m_nMax - m_nPage;
  208.     }
  209.  
  210.     thumb.ul.a[ord] = thumbpos;
  211.     thumb.lr.a[nord] = width;
  212.     thumb.lr.a[ord] = thumbpos + thumblen;
  213.     m_rectThumb = thumb;
  214.  
  215.     temp = track;
  216.     temp.lr.a[ord] = thumb.ul.a[ord];
  217.     if (temp.lr.a[ord] > temp.ul.a[ord])
  218.         m_rectPageUp = temp;
  219.  
  220.     temp = track;
  221.     temp.ul.a[ord] = thumb.lr.a[ord];
  222.     if (temp.lr.a[ord] > temp.ul.a[ord])
  223.         m_rectPageDown = temp;
  224.  
  225.     return m_bValid = TRUE;
  226. #undef FAIL
  227. }
  228.  
  229. void CFlexScrollBar::SetValues(int min, int max, int page, int pos)
  230. {
  231.     m_nMin = min < max ? min : max;
  232.     m_nMax = max > min ? max : min;
  233.     m_nPage = page;
  234.     AdjustPos(pos - m_nPos, TRUE);
  235. }
  236.  
  237. static BOOL UseRect(const RECT &rect)
  238. {
  239.     if (rect.left >= rect.right || rect.bottom <= rect.top)
  240.         return FALSE;
  241.     return TRUE;
  242. }
  243.  
  244. static void Rectangle(HDC hDC, RECT rect)
  245. {
  246.     if (!UseRect(rect))
  247.         return;
  248.  
  249.     Rectangle(hDC, rect.left, rect.top, rect.right, rect.bottom);
  250. }
  251.  
  252. void CFlexScrollBar::OnPaint(HDC hDC)
  253. {
  254.     HDC hBDC = NULL, hODC = NULL;
  255.     CBitmap *pbm = NULL;
  256.  
  257.     if (!InRenderMode())
  258.     {
  259.         hODC = hDC;
  260.         pbm = CBitmap::Create(GetClientSize(), RGB(0,0,0), hDC);
  261.         if (pbm != NULL)
  262.         {
  263.             hBDC = pbm->BeginPaintInto();
  264.             if (hBDC != NULL)
  265.             {
  266.                 hDC = hBDC;
  267.             }
  268.         }
  269.     }
  270.  
  271.     InternalPaint(hDC);
  272.  
  273.     if (!InRenderMode())
  274.     {
  275.         if (pbm != NULL)
  276.         {
  277.             if (hBDC != NULL)
  278.             {
  279.                 pbm->EndPaintInto(hBDC);
  280.                 pbm->Draw(hODC);
  281.             }
  282.             delete pbm;
  283.         }
  284.     }
  285. }
  286.  
  287. void CFlexScrollBar::InternalPaint(HDC hDC)
  288. {
  289.     HGDIOBJ hPen, hOldPen, hBrush, hOldBrush;
  290.     hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbBk);
  291.     if (hPen != NULL)
  292.     {
  293.         hOldPen = SelectObject(hDC, hPen),
  294.         hOldBrush = SelectObject(hDC, GetStockObject(BLACK_BRUSH));
  295.  
  296.         Rectangle(hDC, m_rectPageUp);
  297.         Rectangle(hDC, m_rectPageDown);
  298.         Rectangle(hDC, m_rectLineUp);
  299.         Rectangle(hDC, m_rectLineDown);
  300.  
  301.         SelectObject(hDC, hOldPen);
  302.         DeleteObject(hPen);
  303.  
  304.         hBrush = (HGDIOBJ)CreateSolidBrush(m_rgbFill);
  305.         if (hBrush != NULL)
  306.         {
  307.             SelectObject(hDC, (HGDIOBJ)hBrush);
  308.  
  309.             hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbFill);
  310.             if (hPen != NULL)
  311.             {
  312.                 SelectObject(hDC, hPen);
  313.  
  314.                 Rectangle(hDC, m_rectThumb);
  315.  
  316.                 SelectObject(hDC, hOldPen);
  317.                 DeleteObject(hPen);
  318.             }
  319.  
  320.             hPen = (HGDIOBJ)CreatePen(PS_SOLID, 1, m_rgbLine);
  321.             if (hPen != NULL)
  322.             {
  323.                 SelectObject(hDC, hPen);
  324.  
  325.                 // draw the two arrows for this scrollbar
  326.                 for (int i = 0; i < 2; i++)
  327.                     DrawArrow(hDC, i ? m_rectLineUp : m_rectLineDown, m_bVert, i);
  328.  
  329.     #if 0
  330.                 // draw the two arrows for this scrollbar
  331.                 for (int i = 0; i < 2; i++)
  332.                 {
  333.                     const RECT &rect = i == 0 ? m_rectLineUp : m_rectLineDown;
  334.                     SRECT srect = rect;
  335.                     srect.right--;
  336.                     srect.bottom--;
  337.                     int ord = m_bVert ? 1 : 0;
  338.                     int nord = m_bVert ? 0 : 1;
  339.                     SPOINT p(i ? srect.lr : srect.ul), b(i ? srect.ul : srect.lr);
  340.                     b.a[ord] += 2 * i - 1;
  341.                     SPOINT t = p;
  342.                     t.a[nord] = (p.a[nord] + b.a[nord]) / 2;
  343.                     SPOINT u;
  344.                     u.a[ord] = b.a[ord];
  345.                     u.a[nord] = p.a[nord];
  346.                     POINT poly[] = { {t.x, t.y}, {u.x, u.y}, {b.x, b.y} };
  347.                     Polygon(hDC, poly, 3);
  348.                 }
  349.     #endif
  350.  
  351.                 SelectObject(hDC, hOldPen);
  352.                 DeleteObject(hPen);
  353.             }
  354.         
  355.             SelectObject(hDC, hOldBrush);
  356.             DeleteObject(hBrush);
  357.         }
  358.     }
  359. }
  360.  
  361. BOOL InRect(const RECT &rect, POINT point)
  362. {
  363.     return UseRect(rect) && PtInRect(&rect, point);
  364. }
  365.  
  366. LRESULT CFlexScrollBar::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  367. {
  368.     switch (msg)
  369.     {
  370.         case WM_SIZE:
  371.             Calc();
  372.             Invalidate();
  373.             return 0;
  374.  
  375.         // make sure flexwnd doesn't do ANYTHING with our mouse messages
  376.         case WM_MOUSEMOVE:
  377.         case WM_LBUTTONUP:
  378.         case WM_LBUTTONDOWN:
  379.         case WM_RBUTTONUP:
  380.         case WM_RBUTTONDOWN:
  381.         case WM_LBUTTONDBLCLK:
  382.         case WM_RBUTTONDBLCLK:
  383.         {
  384.             POINT point = {int(signed short(LOWORD(lParam))), int(signed short(HIWORD(lParam)))};
  385.             m_point = point;
  386.             m_code = HitTest(point);
  387.         }
  388.         case WM_TIMER:
  389.         case WM_CAPTURECHANGED:
  390.             break;
  391.         default:
  392.             return CFlexWnd::WndProc(hWnd, msg, wParam, lParam);
  393.     }
  394.  
  395.     switch (msg)
  396.     {
  397.         case WM_LBUTTONDOWN:
  398.         case WM_LBUTTONDBLCLK:
  399.             if (m_code == SB_ENDSCROLL)
  400.                 goto endscroll;
  401.             if (m_code == SB_THUMBTRACK)
  402.                 m_bDragging = TRUE;
  403.             else
  404.                 SetTimer(m_hWnd, 1, 500, NULL);
  405.             m_startcode = m_code;
  406.             m_startpoint = m_point;
  407.             m_nPreDragPos = m_nPos;
  408.             m_bCapture = TRUE;
  409.             SetCapture();
  410.             if (!m_bDragging)
  411.                 Notify(m_code);
  412.             break;
  413.  
  414.         case WM_LBUTTONUP:
  415.         case WM_MOUSEMOVE:
  416.             if (!m_bDragging)
  417.                 break;
  418.             if (Calc())
  419.             {
  420.                 Invalidate();
  421.                 // Force repaint the updated scrollbar position.  If we don't do this,
  422.                 // the WM_PAINT message will be pre-empted by the WM_FLEXVSCROLL messages.
  423.                 // Sometimes this happens during the entire duration of draggin the scroll
  424.                 // bar.  The result is that the scroll bar does not get updated when
  425.                 // dragging.
  426.                 SendMessage(m_hWnd, WM_PAINT, 0, 0);
  427.             }
  428.             Notify(m_startcode);
  429.             break;
  430.  
  431.         case WM_TIMER:
  432.             if (m_bCapture) switch (wParam)
  433.             {
  434.                 case 1:
  435.                     KillTimer(m_hWnd, 1);
  436.                     SetTimer(m_hWnd, 2, 50, NULL);
  437.                 case 2:
  438.                     if (m_bDragging)
  439.                         break;
  440.                     if (m_code == m_startcode)
  441.                         Notify(m_code);
  442.                     break;
  443.             }
  444.             break;
  445.     }
  446.  
  447.     switch (msg)
  448.     {
  449.         case WM_LBUTTONUP:
  450.         case WM_CAPTURECHANGED:
  451.         endscroll:
  452.             if (m_bCapture)
  453.             {
  454.                 m_bCapture = FALSE;
  455.                 KillTimer(m_hWnd, 1);
  456.                 KillTimer(m_hWnd, 2);
  457.                 ReleaseCapture();
  458.                 if (m_bDragging)
  459.                     Notify(SB_THUMBPOSITION);
  460.                 BOOL bWasDragging = m_bDragging;
  461.                 m_bDragging = FALSE;
  462.                 if (bWasDragging)
  463.                 {
  464.                     if (Calc())
  465.                         Invalidate();
  466.                 }
  467.                 Notify(SB_ENDSCROLL);
  468.             }
  469.             break;
  470.     }
  471.  
  472.     return 0;
  473. }
  474.  
  475. void CFlexScrollBar::Notify(int code)
  476. {
  477.     if (!m_hWndNotify)
  478.         return;
  479.  
  480.     SendMessage(m_hWndNotify, m_bVert ? WM_FLEXVSCROLL : WM_FLEXHSCROLL,
  481.         (WPARAM)code, (LPARAM)(LPVOID)this);
  482. }
  483.  
  484. int CFlexScrollBar::HitTest(POINT point)
  485. {
  486.     if (InRect(m_rectLineUp, point))
  487.         return SB_LINEUP;
  488.     else if (InRect(m_rectLineDown, point))
  489.         return SB_LINEDOWN;
  490.     else if (InRect(m_rectThumb, point))
  491.         return SB_THUMBTRACK;
  492.     else if (InRect(m_rectPageUp, point))
  493.         return SB_PAGEUP;
  494.     else if (InRect(m_rectPageDown, point))
  495.         return SB_PAGEDOWN;
  496.     else
  497.         return SB_ENDSCROLL;
  498. }
  499.  
  500. void CFlexScrollBar::SetColors(COLORREF bk, COLORREF fill, COLORREF line)
  501. {
  502.     m_rgbBk = bk;
  503.     m_rgbFill = fill;
  504.     m_rgbLine = line;
  505.     Invalidate();
  506. }
  507.